package vboot.core.security.authc;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import vboot.core.common.dao.JdbcDao;
import vboot.core.common.init.SysApiCache;
import vboot.core.common.init.Yapi;
import vboot.core.security.pojo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Transactional(rollbackFor = Exception.class)
public class AuthcService {

    public void initZuser(Zuser zuser, UserDo userDo, Map<String, Object> backMap) {
        if (!userDo.getRetag()) {
            //1.获取用户所有的组织架构集:conds
            String conds = findConds(userDo);
            zuser.setConds(conds);

            //2.根据组织架构集conds查询前台菜单集:menus
            List<Zmenu> menuList;
            List<Zportal> portalList;
            if (zuser.isAdmin()) {
                portalList = findAllPortalList();
                menuList = findSysMenuList(portalList.get(0).getId());
            } else {
                portalList = findPortalList(zuser.getConds());
                if (portalList != null && portalList.size() > 0) {
                    menuList = findMenuList(zuser.getConds(), portalList, portalList.get(0).getId());
                } else {
                    menuList = findNoPowerMenuList();
                }
            }

            //3.根据组织架构集conds查询前台按钮集:btns
            // 设置zuser的权限集（位与代码方式的权限集）
            List<String> btnList = findBtnList(zuser);

            //4.设置前台返回数据
            menuList = buildByRecursive(menuList);
            backMap.put("portals", portalList);
            backMap.put("menus", menuList);
            backMap.put("btns", btnList);
            backMap.put("zuser", zuser);

            //5.更新用户，序列化保存数据，使下次这些数据可直接从数据库取
            updateUser(zuser, menuList, btnList, portalList);
            System.out.println("通过数据库");

        } else {
            String sql = "select conds,menus,btns,perms,portals from sys_org_user_cache where id=?";
            Map<String, Object> map = jdbcDao.findMap(sql, zuser.getId());
            zuser.setConds((String) map.get("conds"));

            List<Zmenu> menuList = JSON.parseArray((String) map.get("menus"), Zmenu.class);
            List<Zportal> portalList = JSON.parseArray((String) map.get("portals"), Zportal.class);

            String[] btnArr = null;
            String btns = (String) map.get("btns");
            if (btns != null) {
                btnArr = btns.split(";");
            }

            String[] permStrArr = null;
            String perms = (String) map.get("perms");
            if (perms != null) {
                permStrArr = perms.split(";");
            }
            long[] permLongArr = new long[permStrArr.length];
            for (int i = 0; i < permStrArr.length; i++) {
                permLongArr[i] = Long.parseLong(permStrArr[i]);
            }
            zuser.setPermArr(permLongArr);

            backMap.put("menus", menuList);
            backMap.put("portals", portalList);
            backMap.put("btns", btnArr);
            backMap.put("zuser", zuser);
            System.out.println("通过缓存");
        }

//            //初始化数据库user
//            String perms = "";
//            for (int i = 0; i < permSum.length; i++) {
//                perms += permSum[i] + ";";
//            }
//            if (!perms.equals("")) {
//                perms = perms.substring(0, perms.length() - 1);
//            } else {
//                perms = "0";
//            }
//            updatePerson(perms, conds, id);
//            zuser = new Zuser(id, "" + orgInfo.get("name"), sysOrgUser.getUsnam(), permSum, conds);
//            zuser.setAdmin(XuserUtil.isAdmin(sysOrgUser.getUsnam()));
//            zuser.setWatag(sysOrgUser.getWatag());
//        } else {
//            String[] permArr = sysOrgUser.getPerms().split(";");
//            long[] permSum = new long[permArr.length];
//            for (int i = 0; i < permArr.length; i++) {
//                permSum[i] = Long.parseLong(permArr[i]);
//            }
//            zuser = new Zuser(id, "" + orgInfo.get("name"), "" + sysOrgUser.getUsnam(), permSum, sysOrgUser.getConds());
//            zuser.setAdmin(XuserUtil.isAdmin(sysOrgUser.getUsnam()));
//            zuser.setWatag(sysOrgUser.getWatag());
//        }
//        return zuser;


    }

    public void initZuser2(Zuser zuser, Map<String, Object> backMap, String porid) {
        //2.根据组织架构集conds查询前台菜单集:menus
        List<Zmenu> menuList;
        List<Zportal> portalList;
        if (zuser.isAdmin()) {
            portalList = findAllPortalList();
            menuList = findSysMenuList(porid);
        } else {
            portalList = findPortalList(zuser.getConds());
            if (portalList != null && portalList.size() > 0) {
                menuList = findMenuList(zuser.getConds(), portalList, porid);
            } else {
                menuList = findNoPowerMenuList();
            }
        }

        //4.设置前台返回数据
        menuList = buildByRecursive(menuList);
        backMap.put("portals", portalList);
        backMap.put("menus", menuList);
    }

//    private void calcPerms(Zuser zuser,){
//        //查询权限集合
//            Integer posSum = SysPermApiService.AUTHPOS + 1;//取出最大权限位
//            long[] permSum = new long[posSum];
////
//            List<Zperm> zpermList = getPermList(conds);
//            for (Zperm zperm : zpermList) {
//                for (int i = 0; i < posSum; i++) {
//                    if (i == zperm.getPos()) {
//                        permSum[i] = permSum[i] + zperm.getCode();
//                    }
//                }
//            }
//    }

    private void setPerms(Zuser zuser, List<Zmenu> zmenus) {

    }

    private String findConds(UserDo duser) {
        StringBuilder conds = new StringBuilder();
        //1. conds拼接父级id
        if (StrUtil.isNotBlank(duser.getTier())) {
            String[] pidArr = duser.getTier().split("x");
            for (int i = pidArr.length - 1; i >= 0; i--) {
                if (!"".equals(pidArr[i])) {
                    conds.append("'").append(pidArr[i]).append("',");
                }
            }
        } else {
            conds = new StringBuilder("'" + duser.getId() + "',");
        }
        //2. conds拼接岗位id
        List<String> postList = findPostList(duser.getId());
        for (String str : postList) {
            conds.append("'").append(str).append("',");
        }
        conds = new StringBuilder(conds.substring(0, conds.length() - 1));//优化
        //3. conds拼接群组id
        List<String> groupList = findGroupList(conds.toString());
        for (String str : groupList) {
            conds.append(",'").append(str).append("'");
        }
        return conds.toString();
    }


    private List<String> findPostList(String uid) {
        String sql = "select pid as id from sys_org_post_org where oid=?";
        return jdbcDao.findStringList(sql, uid);
    }

    private List<String> findGroupList(String conds) {
        String sql = "select DISTINCT gid as id from sys_org_group_org where oid in (" + conds + ")";
        return jdbcDao.findStringList(sql);
    }

    public List<Zportal> findPortalList(String conds) {
        String sql = "select distinct m.name,m.id from sys_portal_main m inner join sys_portal_role r on r.porid=m.id" +
                " inner join sys_portal_role_org ro on ro.rid=r.id where m.avtag=1 and ro.oid in (" + conds + ") order by m.ornum";
        return jdbcDao.getTp().query(sql, new BeanPropertyRowMapper<>(Zportal.class));
    }

    public List<Zmenu> findMenuList(String conds, List<Zportal> portalList, String porid) {
        String portals = "";
        for (Zportal zportal : portalList) {
            portals += "'" + zportal.getId() + "',";
        }
        portals = portals.substring(0, portals.length() - 1);

        String direSql = "select m.porid,m.shtag,m.name,m.code,m.path,m.icon,m.comp,m.ornum,m.id,m.pid,m.perm from sys_portal_menu m where m.type = 'D' and m.porid in (" + portals + ") and m.avtag=1 order by m.ornum";
        List<Zmenu> direList = jdbcDao.getTp().query(direSql, (rs, rowNum) -> {
            Zmenu zmenu = new Zmenu();
            zmenu.setType("D");
            zmenu.setId(rs.getString("id"));
            zmenu.setPorid(rs.getString("porid"));
            zmenu.setPid(rs.getString("pid"));
            zmenu.setPerm(rs.getString("perm"));
            zmenu.setName(rs.getString("code"));
            zmenu.setPath(rs.getString("path"));
            zmenu.setComponent(rs.getString("comp"));
            Zmeta zmeta = new Zmeta();
            zmeta.setTitle(rs.getString("name"));
            zmeta.setOrderNo(rs.getInt("ornum"));
            zmeta.setIsHide(!rs.getBoolean("shtag"));
            if (!porid.equals(rs.getString("porid"))) {
                zmeta.setIsHide(true);
            }
            zmeta.setIcon(rs.getString("icon"));
            zmenu.setMeta(zmeta);
            return zmenu;
        });

        String sql = "select distinct m.porid,m.shtag,m.type,m.name,m.code,m.path,m.icon,m.comp,m.ornum,m.id,m.pid,m.perm from sys_portal_menu m inner join sys_portal_role_menu rm on rm.mid=m.id inner join sys_portal_role_org ru on ru.rid=rm.rid where m.type = 'M' and m.porid in (" + portals + ") and m.avtag=1 and ru.oid in (" + conds + ") order by m.ornum";

        List<Zmenu> list = jdbcDao.getTp().query(sql, (rs, rowNum) -> {
            Zmenu zmenu = new Zmenu();
            zmenu.setId(rs.getString("id"));
            zmenu.setType("M");
            zmenu.setPorid(rs.getString("porid"));
            zmenu.setPid(rs.getString("pid"));
            zmenu.setPerm(rs.getString("perm"));
            zmenu.setName(rs.getString("code"));
            zmenu.setPath(rs.getString("path"));
            zmenu.setComponent(rs.getString("comp"));
            Zmeta zmeta = new Zmeta();
            zmeta.setTitle(rs.getString("name"));
            zmeta.setIsHide(!rs.getBoolean("shtag"));
            if (!porid.equals(rs.getString("porid"))) {
                zmeta.setIsHide(true);
            }
            zmeta.setOrderNo(rs.getInt("ornum"));
            zmeta.setIcon(rs.getString("icon"));
            zmenu.setMeta(zmeta);
            return zmenu;
        });

        List<Zmenu> shouldAddlist1 = new ArrayList<>();
        for (Zmenu zdire : direList) {
            for (Zmenu zmenu : list) {
                if (zdire.getId().equals(zmenu.getPid())) {
                    shouldAddlist1.add(zdire);
                    break;
                }
            }
        }

        List<Zmenu> shouldAddlist2 = new ArrayList<>();
        for (Zmenu zdire : direList) {
            for (Zmenu zshould : shouldAddlist1) {
                if (zshould.getPid() != null) {
                    if (zdire.getId().equals(zshould.getPid())) {
                        shouldAddlist2.add(zdire);
                        break;
                    }
                }
            }
        }

        List<Zmenu> shouldAddlist3 = new ArrayList<>();
        for (Zmenu zdire : direList) {
            for (Zmenu zshould : shouldAddlist2) {
                if (zshould.getPid() != null) {
                    if (zdire.getId().equals(zshould.getPid())) {
                        shouldAddlist3.add(zdire);
                        break;
                    }
                }
            }
        }
        list.addAll(shouldAddlist1);
        list.addAll(shouldAddlist2);
        list.addAll(shouldAddlist3);
        if (list.size() == 0) {
            return findNoPowerMenuList();
        }
        if (portalList.size() == 1) {
            return list;
        }
        //去除其他门户相同name或path的菜单
        List<Zmenu> backList = new ArrayList<>();
        for (Zmenu zmenu : list) {
            if (porid.equals(zmenu.getPorid())) {
                backList.add(zmenu);
            }
        }
        for (Zmenu zmenu : list) {
            if (!porid.equals(zmenu.getPorid())) {
                boolean flag = false;
                for (Zmenu backMenu : backList) {
                    if (backMenu.getName().equals(zmenu.getName()) || backMenu.getPath().equals(zmenu.getPath())) {
                        flag = true;
                        break;
                    }
                }
                if (!flag) {
                    backList.add(zmenu);
                }
            }
        }
        return backList;
    }

    public List<Zportal> findAllPortalList() {
        String sql = "select id,name from sys_portal_main where avtag=1 order by ornum";
        return jdbcDao.getTp().query(sql, new BeanPropertyRowMapper<>(Zportal.class));
    }


    public List<Zmenu> findSysMenuList(String porid) {
//        String sql = "select m.shtag,m.type,m.name,m.code,m.path,m.icon,m.comp,m.ornum,m.id,m.pid,m.perm from sys_portal_menu m where m.porid='sys' and m.avtag=1 order by m.ornum";
        String sql = "select m.porid,m.shtag,m.type,m.name,m.code,m.path,m.icon,m.comp,m.ornum,m.id,m.pid,m.perm from sys_portal_menu m where  m.avtag=1 order by m.ornum";
        List<Zmenu> list = jdbcDao.getTp().query(sql, (rs, rowNum) -> {
            Zmenu zmenu = new Zmenu();
            zmenu.setId(rs.getString("id"));
            zmenu.setPorid(rs.getString("porid"));
            zmenu.setPid(rs.getString("pid"));
            zmenu.setPerm(rs.getString("perm"));
            zmenu.setType(rs.getString("type"));
            zmenu.setName(rs.getString("code"));
            zmenu.setPath(rs.getString("path"));
            zmenu.setComponent(rs.getString("comp"));
            Zmeta zmeta = new Zmeta();
            zmeta.setIsHide(!rs.getBoolean("shtag"));
            if (!porid.equals(rs.getString("porid"))) {
                zmeta.setIsHide(true);
            }
            zmeta.setTitle(rs.getString("name"));
            zmeta.setOrderNo(rs.getInt("ornum"));
            zmeta.setIcon(rs.getString("icon"));
            zmenu.setMeta(zmeta);
            return zmenu;
        });
        //去除其他门户相同name或path的菜单
        List<Zmenu> backList = new ArrayList<>();
        for (Zmenu zmenu : list) {
            if (porid.equals(zmenu.getPorid())) {
                backList.add(zmenu);
            }
        }
        for (Zmenu zmenu : list) {
            if (!porid.equals(zmenu.getPorid())) {
                boolean flag = false;
                for (Zmenu backMenu : backList) {
                    if (backMenu.getName().equals(zmenu.getName()) || backMenu.getPath().equals(zmenu.getPath())) {
                        flag = true;
                        break;
                    }
                }
                if (!flag) {
                    backList.add(zmenu);
                }
            }
        }
        return backList;
    }

    public List<Zmenu> findNoPowerMenuList() {
        List<Zmenu> list = new ArrayList<>();
        Zmenu zmenu = new Zmenu();
        zmenu.setType("M");
        zmenu.setId("Home");
        zmenu.setName("Home");
        zmenu.setPath("/home");
        zmenu.setComponent("/home/noPower");
        Zmeta zmeta = new Zmeta();
        zmeta.setTitle("未授权");
        zmeta.setOrderNo(0);
        zmeta.setIsHide(false);
        zmeta.setIcon("ele-Lock");
        zmenu.setMeta(zmeta);
        list.add(zmenu);
        return list;
    }


//    //使用递归方法建树
//    private List<Zmenu> buildTree(List<Zmenu> treeNodes) {
//        List<Zmenu> trees = new ArrayList<>();
//        for (Zmenu treeNode : treeNodes) {
//            if (treeNode.getPid() == null) {
//                trees.add(recTree(treeNode, treeNodes));
//            }
//        }
//        return trees;
//    }
//
//
//    //递归查找子节点
//    private Zmenu recTree(Zmenu treeNode, List<Zmenu> treeNodes) {
//        for (Zmenu it : treeNodes) {
//            if (treeNode.getId().equals(it.getPid())) {
//                if (treeNode.getChildren() == null) {
//                    treeNode.setChildren(new ArrayList<>());
//                }
//                treeNode.getChildren().add(recTree(it, treeNodes));
//            }
//        }
//        return treeNode;
//    }


    //使用递归方法建树
    private List<Zmenu> buildByRecursive(List<Zmenu> nodes)
    {
        List<Zmenu> list = new ArrayList<>();
        for (Zmenu node : nodes) {
            if (node.getPid() == null)
            {
                list.add(findChildrenByTier(node, nodes));
            }
            else
            {
                boolean flag = false;
                for (Zmenu node2 : nodes) {
                    if (node.getPid().equals(node2.getId()))
                    {
                        flag = true;
                        break;
                    }
                }
                if (!flag)
                {
                    list.add(findChildrenByTier(node, nodes));
                }
            }
        }
        return list;
    }

    //递归查找子节点
    private Zmenu findChildrenByTier(Zmenu node, List<Zmenu> nodes)
    {
        for (Zmenu item : nodes) {
            if (node.getId().equals(item.getPid()))
            {
                if (node.getChildren() == null)
                {
                    node.setChildren(new ArrayList<>());
                }
                node.getChildren().add(findChildrenByTier(item, nodes));
            }
        }
        return node;
    }


    private List<Yapi> findYapiList(String conds) {
        String sql = "select distinct m.id url,m.pos,m.code from sys_api_main m " +
                "inner join sys_api_role_api rm on rm.mid=m.id " +
                "inner join sys_api_role_org ru on ru.rid=rm.rid " +
                "where  m.avtag=1 and ru.oid in (" + conds + ") and code<>0";
        return jdbcDao.getTp().query(sql, new BeanPropertyRowMapper<>(Yapi.class));
    }


    private List<String> findBtnList(Zuser zuser) {
        List<String> btnList = new ArrayList<>();
        List<Yapi> apiList = findYapiList(zuser.getConds());
        int posSum = SysApiCache.AUTHPOS + 1;
        long[] permArr = new long[posSum];
        for (Yapi api : apiList) {
            for (int i = 0; i < posSum; i++) {
                if (i == api.getPos()) {
                    permArr[i] += api.getCode();
                }
            }
            btnList.add(api.getUrl());
        }
        zuser.setPermArr(permArr);
        return btnList;
    }


    private void updateUser(Zuser zuser, List<Zmenu> menuList, List<String> btnList, List<Zportal> portalList) {

        String menus = JSON.toJSONString(menuList);
        String portals = JSON.toJSONString(portalList);
        StringBuilder btns = new StringBuilder();
        for (String str : btnList) {
            btns.append(str).append(";");
        }

        StringBuilder perms = new StringBuilder();
        for (long perm : zuser.getPermArr()) {
            perms.append(perm).append(";");
        }

        String existSql = "select count(*) from sys_org_user_cache where id=?";
        Integer integer = jdbcDao.getTp().queryForObject(existSql, new Object[]{zuser.getId()}, Integer.class);
        if (integer > 0) {
            String sql = "update sys_org_user_cache set conds=?,menus=?,btns=?,perms=?,portals=? where id=?";
            jdbcDao.update(sql, zuser.getConds(), menus, btns.toString(), perms.toString(), portals, zuser.getId());
        } else {
            String sql = "insert into sys_org_user_cache(id,conds,menus,btns,perms,portals) VALUES(?,?,?,?,?,?)";
            jdbcDao.update(sql, zuser.getId(), zuser.getConds(), menus, btns.toString(), perms.toString(), portals);
        }
        String retagSql = "update sys_org_user set retag=1 where id=?";
        jdbcDao.update(retagSql, zuser.getId());

    }


    @Transactional(readOnly = true)
    public Zuser getUser(String username) {
        Map<String, Object> map = jdbcDao.getTp().queryForMap("select u.id,u.name from sys_org_user u where u.usnam=? and u.avtag=1", username);
        Zuser user = new Zuser();
        user.setId((String) map.get("id"));
        user.setName((String) map.get("name"));
        return user;
    }


    @Autowired
    private JdbcDao jdbcDao;


}
